#include "server.h"
#include "comment.h"
#include "database.h"

// 用来存放客户端的套接字FD和用户名的数组
ONLINE clientFdArr[1024];
// 已经有多少个客户端连接
int connected = 0;
// 数据库的指针
sqlite3 * pDB;

// 当参数isAdd为1的时候，添加用户的套接字clientFd到数组
// 当参数isAdd不为1的时候，将用户的套接字clientFd从数组删除
// 第二个参数只有添加用户的时候使用，当删除用户的时候不需要，因为删除用户只比较套接字不需要用户名
void addNewClient(int clientFd, char * name , int isAdd)
{
     if (isAdd == 1) // 添加
     {
          // printf("handleEvent收到连接事件，调用添加用户的函数，总用户数更新为：%d\n", connected);
          clientFdArr[connected].fd = clientFd;
          strcpy(clientFdArr[connected].name,name);
          connected++;
          printf("服务器当前在线人数：%d\n", connected);
     }
     else // 删除
     {
          // 还需要从客户端数组中删除该套接字FD
          for (size_t i = 0; i < connected; i++)
          {
               // 判断被失效的套接字是不是客户端数组中的第i个元素，如果是的就从数组中删除它
               if (clientFd == clientFdArr[i].fd)
               {
                    // 从要删除的位置的后一个开始，逐个往前移动
                    for (int j = i + 1; j < connected; j++)
                    {
                         printf("handleEvent发现有套接字失效，删除了失效套接字\n");
                         clientFdArr[j - 1] = clientFdArr[j];
                    }
                    // 总数量-1
                    connected--;
                    printf("服务器当前在线人数：%d\n", connected);
               }
          }
     }
}

// 是在handleEvent函数收到通信消息时被调用的，handleEvent函数会把消息内容通过参数传进来
// clientfd和pBuf分别是消息发送者和消息的内容
void work(int clientfd, char *pBuf)
{
     //把缓冲区还原成结构体
     NETNODE * pMsg = (NETNODE*)pBuf;
     if(pMsg->type == REGISTER)
     {
          //把通信结构题里面的内容还原成用户信息
          //告诉电脑地址里面不是字符，而是一个用户，所以要转成用户信息类型的地址
          USERINFO * pUser = (USERINFO*)pMsg->content;
          char sql[256];
          sprintf(sql, "select name from user where name='%s'",pUser->name);
          //在数据库pDB中执行SQL查询语句
          QUERYRESULT * pQR = query_db(pDB,sql);
          sprintf(sql, "select name from user where  phone='%s'",pUser->tel);
          //在数据库pDB中执行SQL查询语句
          QUERYRESULT * pQR1 = query_db(pDB,sql);
          if (pQR->row!=0||pQR1->row!=0)
          {    
               if (pQR->row!=0)
               {
                    sprintf(sql,"用户名:%s已被注册，请重新注册\n",pUser->name);
                    strcpy(pMsg->content,sql); 
               }
               else
               {
                    sprintf(sql,"手机号:%s已被注册，请重新注册\n",pUser->tel);
                    strcpy(pMsg->content,sql);
               }
          }
          else
          {
          //把用户发过来的注册信息构建成一句插入的SQL语句
          sprintf(sql,"INSERT INTO user VALUES ('%s','%s','%s',datetime('now','+08:00'))",pUser->name,pUser->pwd,pUser->tel);
          printf("%s\n",sql);
          //在pDB指向的数据库中执行sql语句
          if(1 == exec_sql(pDB,sql))
          {
               printf("用户注册时插入数据成功\n");
               //直接把通信结构体的类型改为OK，回复给用户
               pMsg->type = OK;

               char sql[256];
               sprintf(sql,"create table %s_firend (name)",pUser->name);
               //执行上面创建表格的SQL语句
               if(1 == exec_sql(pDB,sql))
               {
                    printf("创建好友%s_firend数据表数据表成功\n",pUser->name);
               }
          }
          else
          {
               printf("用户注册时插入数据失败\n");
               //直接把通信结构体的类型改为NO，回复给用户
               pMsg->type = NO;
          }
          }
          //回复客户端的消息（应答）
          write(clientfd,pMsg,MSG_BUF_SIZE);
          // printf("有客户端发来注册消息,我要把这些存入数据库，用户名:%s 密码:%s 电话:%s\n",pUser->name,pUser->pwd,pUser->tel);
     }
     else if(pMsg->type == LOGIN)
     {
          //把通信结构题里面的内容还原成用户信息
          //告诉电脑地址里面不是字符，而是一个用户，所以要转成用户信息类型的地址
          USERINFO * pUser = (USERINFO*)pMsg->content;
          printf("收到用户登录消息,查看是否有用户名是：%s 密码是：%s的用户\n",pUser->name,pUser->pwd);
          char sql[256];
          //构建查询用户名和密码的SQL语句
          sprintf(sql, "select name pwd from user where name='%s' and pwd='%s'", pUser->name, pUser->pwd);
          //在数据库pDB中执行SQL查询语句
          QUERYRESULT * pQR = query_db(pDB,sql);
          //如果一条记录都没有，说明用户传过来的用户名和密码在数据库中不存在
          if(pQR->row == 0)
          {
               printf("用户名或者密码错误\n");
               //直接把通信结构体的类型改为NO，回复给用户
               pMsg->type = NO;
          }
          else
          {
               printf("登录成功\n");
               // 把登录成功的套接字加入到数组中
               addNewClient(clientfd,pUser->name,1);
               //直接把通信结构体的类型改为OK，回复给用户
               pMsg->type = OK;
          }

          //回复客户端的消息（应答）
          write(clientfd,pMsg,MSG_BUF_SIZE);
     }
     else if(pMsg->type == CHAT)//私聊
     {
          CHAT_NODE * pCN = (CHAT_NODE*)pMsg->content;
          //存储附加信息
          char sp[700],name[128];
          char sql[256];
          // strcpy(name,pCN->self);
          // sprintf(sql,"select * from chat_record where acceptor='%s' and state = '0'",pCN->self);  
          // QUERYRESULT * qr =  query_db(pDB,sql);
          // TC  tc;
          // memcpy(pMsg->content,&qr->row,sizeof(qr->row));
          // write(clientfd,pMsg,MSG_BUF_SIZE);
          // printf("共有%d未读消息\n",qr->row);
          // if(qr->row!=0){
          // for (size_t i = qr->col; i <(qr->row+1)*qr->col; i+=qr->col)//(qr->row+1)*qr->col
          // {
          //      strcpy(tc.text,qr->ppResult[i+2]);
          //      strcpy(tc.datatime,qr->ppResult[i+4]);
          //      memcpy(pMsg->content,&tc,sizeof(tc));
          //      write(clientfd,pMsg,MSG_BUF_SIZE);
          //      sprintf(sql,"update chat_record set state='1' where acceptor='%s'",pCN->self);
          //      exec_sql(pDB,sql);
          //      printf("%s %s %s\n",tc.self,tc.text,tc.datatime);
          // }
          //      }
          if (pCN->text!=0)
          {
          sprintf(sql,"insert into chat_record values('%s','%s','%s','0',datetime('now','+08:00'))",pCN->self,pCN->dest,pCN->text);
          exec_sql(pDB,sql); 
          }
          
          
          // int flag = 0 ;
          // char sql[256];
          // sprintf(sql,"insert into group_record values('%s','%s',datetime('now','+08:00'))",pCN->self,pCN->text);
          // exec_sql(pDB,sql);
          
          strcpy(name,pCN->self);
          //在登录数组中去找到名字为pCN->dest的用户，并向该用户转发pMsg结构体即可
          for (size_t i = 0; i < connected; i++)
          {
               //判断第i个登录用户的名字，是不是我们要单聊的对象，如果是就给它的套接字转发消息
               if(strcmp(clientFdArr[i].name,pCN->dest)==0)
               {
                    sprintf(sp,"-接收%s的私聊消息:",pCN->self);
                    strcat(sp,pCN->text);
                    strcpy(pMsg->content,sp);
                    // flag = 1;
                    // pMsg->type = OK ;
                    sprintf(sql,"update chat_record set state='1' where sender='%s'",name);
                    exec_sql(pDB,sql);
                    write(clientFdArr[i].fd,pMsg,MSG_BUF_SIZE);//找到结果发给对方                    
               }                                                             
          }
     }
     else if(pMsg->type == CHAT_GROUP)//群聊
     {
          GCHAT_NODE * gchat = (GCHAT_NODE *)pMsg->content;
          char sql[256];
          sprintf(sql,"insert into group_record values('%s','%s',datetime('now','+08:00'))",gchat->self,gchat->text);
          exec_sql(pDB,sql);
          //存储附加信息
          // char sp[700];//
          char name[128] ;
          strcpy(name,gchat->self);
          for (size_t i = 0; i < connected; i++)
          {
          // printf("1：%s\n",gchat->self);
               //如果不是消息的发送者，就可以把消息转发给这个套接字
               if(clientFdArr[i].fd!=clientfd)
               {
                    if (strcmp(gchat->text,"quit")==0)//输入quit代表退出聊天信息
                    {
                         //存储附加信息
                        char sp[700];//
                        sprintf(sp,"用户%s退出聊天！",name);
                        strcpy(pMsg->content,sp);
                        //直接把通信结构体转发出去，里面携带了客户端输入的聊天信息
                        write(clientFdArr[i].fd,pMsg,MSG_BUF_SIZE);                         
                    }
                    else
                    {
                    //存储附加信息
                    char sp[700];//
                    sprintf(sp,"-群用户%s:",name);
                    // printf("2：%s\n",gchat->self);
                    strcat(sp,gchat->text);
                    strcpy(pMsg->content,sp);
                    //直接把通信结构体转发出去，里面携带了客户端输入的聊天信息
                    write(clientFdArr[i].fd,pMsg,MSG_BUF_SIZE);
                    }
               }
          }
     }
     else if(pMsg->type == MODIFY_PWD)//修改密码
     {
          //把通信结构题里面的内容还原成用户信息
          USERINFO * pUser = (USERINFO*)pMsg->content;
          char sql[256];
          //构建查询用户名和密码的SQL语句
          sprintf(sql, "select name pwd from user where name='%s' and pwd='%s'", pUser->name, pUser->pwd);
          //在数据库pDB中执行SQL查询语句
          QUERYRESULT * pQR = query_db(pDB,sql);
          if (pQR->row!=0)
          {
               
               USERINFO user;
               read(clientfd,&user,sizeof(user));
               printf("%s,%s\n",user.pwd,user.name);
               sprintf(sql,"UPDATE user SET pwd='%s' WHERE name='%s';",user.pwd,user.name);
               if ( 0 != exec_sql(pDB,sql))
               {
                    pMsg->type = OK ;
               }
               else
                    pMsg->type = NO ;
               write(clientfd,pMsg,MSG_BUF_SIZE);
          }
          else
          {
               pMsg->type = NO ;
               write(clientfd,&pMsg,MSG_BUF_SIZE);
          }
          
     }
     else if (pMsg->type == SINGEL_GROUP)
     {
          char sql[256] ;
          sprintf(sql,"select * from group_record where sender = '%s'",pMsg->content);  
          QUERYRESULT * qr =  query_db(pDB,sql);
          TC  tc;
          memcpy(pMsg->content,&qr->row,sizeof(qr->row));
          write(clientfd,pMsg,MSG_BUF_SIZE);
          printf("共有%d消息记录\n",qr->row);
          for (size_t i = qr->col; i <(qr->row+1)*qr->col; i+=qr->col)//(qr->row+1)*qr->col
          {
               strcpy(tc.self,qr->ppResult[i]);
               strcpy(tc.text,qr->ppResult[i+1]);
               strcpy(tc.datatime,qr->ppResult[i+2]);
               memcpy(pMsg->content,&tc,sizeof(tc));
               write(clientfd,pMsg,MSG_BUF_SIZE);
               // printf("%s %s %s\n",tc.self,tc.text,tc.datatime);
          }
          
     }
     else if (pMsg->type == SINGEL_CHAT)
     {
          char sql[256] ;
          sprintf(sql,"select * from chat_record where sender = '%s'",pMsg->content);  
          QUERYRESULT * qr =  query_db(pDB,sql);
          TC  tc;
          memcpy(pMsg->content,&qr->row,sizeof(qr->row));
          write(clientfd,pMsg,MSG_BUF_SIZE);
          printf("共有%d消息记录\n",qr->row);
          for (size_t i = qr->col; i <(qr->row+1)*qr->col; i+=qr->col)//(qr->row+1)*qr->col
          {
               strcpy(tc.self,qr->ppResult[i]);
               strcpy(tc.dest,qr->ppResult[i+1]);
               strcpy(tc.text,qr->ppResult[i+2]);
               strcpy(tc.datatime,qr->ppResult[i+4]);
               memcpy(pMsg->content,&tc,sizeof(tc));
               write(clientfd,pMsg,MSG_BUF_SIZE);
               // printf("%s %s %s %s\n",tc.self,tc.dest,tc.text,tc.datatime);
          }
          
     }
     else if(pMsg->type == LOGOUT)//exit
     {
          // for (size_t i = 0; i < connected; i++)
          // {
          //      if (clientFdArr[i].fd==clientfd)
          //      {
          //           clientFdArr[i].fd=0;
          //           strcpy(clientFdArr[i].name,NULL);
          //           connected--;
          //      }
               
          // }
          
          return ;
     }
}



int main()
{
     //创建/打开book.db数据库
     pDB = openDatabase("./database/database.db");

     // char * pSql = "select * from user order by tel";
     // QUERYRESULT * pQR = query_db(pDB,pSql);
     // printf("一共有%d条记录%d\n",pQR->row,pQR->col);
     // for (size_t i = 0; i < 21; i++)
     // {
     //      printf("%s ",pQR->ppResult[i]);
     //      if((i+1)%3 == 0)
     //      {
     //           printf("\n");
     //      }
     // }
     char * pSql = "create table user (name,pwd,phone,date) ";
     //执行上面创建表格的SQL语句
     if(1 == exec_sql(pDB,pSql))
     {
          printf("创建数据表成功\n");
     }
     //创建好友申请表
     exec_sql(pDB,"create table freind_msg (sender,accpetor,state,datetime)");
     //创建私聊总表
     exec_sql(pDB,"create table chat_record (sender,acceptor,message,state,datetime)");
     //创建群聊总表
     exec_sql(pDB,"create table group_record (sender,message,datetime)");
     //表格创建成功后，在work收到用户注册消息的时候，就把用户信息存入到表格中
     // 初始化服务器
     int epObj = initServer("192.168.95.128", 9000);
     //服务器消息处理函数，要求传入添加用户（addNewClient）和消息（work）处理函数
     //当有客户端离开的时候handleEvent会调用addNewClient函数，从数组中删除该客户端
     //当收到客户端发来的通信消息时handleEvent会调用work函数
     handleEvent(epObj, addNewClient, work);
     return 0;
}